package com.zlf.sb.demo.service.impl;

import com.zlf.sb.demo.util.DateUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.HashMap;
import java.util.List;

/**
 * @author zlf
 * @description:
 * @time: 2022/9/7 9:58
 */
@Slf4j
@Data
public class TimeLoopService {

    /**
     * 夜间开始时长点数
     */
    private int start;

    /**
     * 夜间结束时长点数
     */
    private int end;

    /**
     * 入场时间
     */
    private LocalDateTime goInStart;

    /**
     * 入场时钟的开始计费点
     */
    private LocalDateTime goInStartClockTime;

    /**
     * 入场时钟结束计费点
     */
    private LocalDateTime goInEndClockTime;

    /**
     * 入场 minClock 00:00:00
     */
    private LocalDateTime goInPassMinTime;

    /**
     * 入场 maxClock 23:59:59
     */
    private LocalDateTime goInPassMaxTime;

    /**
     * 入场月的最后一天
     */
    private Integer goInMothLastDay;

    /**
     * 出场时间
     */
    private LocalDateTime goOutEnd;

    /**
     * 出场时钟的开始计费点
     */
    private LocalDateTime goOutStartClockTime;

    /**
     * 出场时钟结束计费点
     */
    private LocalDateTime goOutEndClockTime;

    /**
     * 出场 minClock 00:00:00
     */
    private LocalDateTime goOutPassMinTime;

    /**
     * 出场clock 23:59:59
     */
    private LocalDateTime goOutPassMaxTime;

    /**
     * 出场月的第一天
     */
    private Integer goOutMothFirstDay;

    /**
     * 入场时间和出场时间相差几天
     */
    private int lessDay;

    /**
     * 一个时钟周期的免费时长小时数
     */
    private int oneClockFreeHours;

    /**
     * 00:00:00
     */
    private String psMinStr = "00:00:00";

    /**
     * 23:59:59
     */
    private String psMaxStr = "23:59:59";

    /**
     * 00:00
     */
    private String oo = "00:00";

    private HashMap<String, Integer> goInStartMap = new HashMap<>();

    private HashMap<String, Integer> goOutEndMap = new HashMap<>();

    private Boolean flag1 = Boolean.FALSE;


    public TimeLoopService(Integer start, Integer end, LocalDateTime goInStart, LocalDateTime goOutEnd) {
        this.start = start;
        this.end = end;
        this.goInStart = goInStart;
        this.goOutEnd = goOutEnd;

        oneClockFreeHours = 24 - Math.abs((start - end));
        log.info("oneClockFreeHours:{}", oneClockFreeHours);

        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        String gs = dateTimeFormatter1.format(goInStart);
        LocalDate startDt = LocalDate.parse(gs, dateTimeFormatter1);
        int start_Y = startDt.getYear();
        int start_M = startDt.getMonth().getValue();
        int start_D = startDt.getDayOfMonth();
        String[] s = gs.split(" ");
        String[] s2 = s[1].split(":");
        int start_H = Integer.valueOf(s2[0]).intValue();
        int start_MM = Integer.valueOf(s2[1]).intValue();
        int start_S = Integer.valueOf(s2[2]).intValue();
        goInStartMap.put("start_Y", start_Y);
        goInStartMap.put("start_M", start_M);
        goInStartMap.put("start_D", start_D);
        goInStartMap.put("start_H", start_H);
        goInStartMap.put("start_MM", start_MM);
        goInStartMap.put("start_S", start_S);
        log.info("开始时间各分量：Y=" + start_Y + ",M=" + start_M + ",D=" + start_D + ",H=" + start_H + ",MM:" + start_MM + ",start_S:" + start_S);

        String ge = dateTimeFormatter1.format(goOutEnd);
        LocalDate endDt = LocalDate.parse(ge, dateTimeFormatter1);
        int start_Y1 = endDt.getYear();
        int start_M1 = endDt.getMonth().getValue();
        int start_D1 = endDt.getDayOfMonth();
        String[] s3 = ge.split(" ");
        String[] s4 = s3[1].split(":");
        int start_H1 = Integer.valueOf(s4[0]).intValue();
        int start_MM1 = Integer.valueOf(s4[1]).intValue();
        int start_S1 = Integer.valueOf(s4[2]).intValue();
        goOutEndMap.put("start_Y1", start_Y1);
        goOutEndMap.put("start_M1", start_M1);
        goOutEndMap.put("start_D1", start_D1);
        goOutEndMap.put("start_H1", start_H1);
        goOutEndMap.put("start_MM1", start_MM1);
        goOutEndMap.put("start_S1", start_S1);
        log.info("结束时间各分量：Y1=" + start_Y1 + ",M1=" + start_M1 + ",D1=" + start_D1 + ",H1=" + start_H1 + ",MM1:" + start_MM1 + ",start_S1:" + start_S1);

        String startStr = "";
        if (0 < start && start <= 9) {
            startStr = "0" + start;
        } else {
            startStr = start.toString();
        }
        log.info("startStr:{}", startStr);

        String endStr = "";
        if (0 < end && end <= 9) {
            endStr = "0" + end;
        } else {
            endStr = end.toString();
        }
        log.info("endStr:{}", endStr);

        String start_M_str = "";
        if (start_M <= 9) {
            start_M_str = "0" + start_M;
        } else {
            start_M_str = String.valueOf(start_M);
        }
        log.info("start_M_str:{}", start_M_str);

        String start_M_str1 = "";
        if (start_M1 <= 9) {
            start_M_str1 = "0" + start_M1;
        } else {
            start_M_str1 = String.valueOf(start_M1);
        }
        log.info("start_M_str1:{}", start_M_str1);

        String start_D_str = "";
        if (start_D <= 9) {
            start_D_str = "0" + start_D;
        } else {
            start_D_str = String.valueOf(start_D);
        }
        log.info("start_D_str:{}", start_D_str);

        String start_D_str1 = "";
        if (start_D1 <= 9) {
            start_D_str1 = "0" + start_D1;
        } else {
            start_D_str1 = String.valueOf(start_D1);
        }
        log.info("start_D_str1:{}", start_D_str1);

        goInStartClockTime = DateUtils.stringToLocalDateTime(start_Y + "-" + start_M_str + "-" + start_D_str + " " + startStr + ":" + oo);
        log.info("goInStartClockTime:{}", DateUtils.localDateTimeToString(goInStartClockTime));

        goInEndClockTime = DateUtils.stringToLocalDateTime(start_Y + "-" + start_M_str + "-" + start_D_str + " " + endStr + ":" + oo);
        log.info("goInEndClockTime:{}", DateUtils.localDateTimeToString(goInEndClockTime));

        goInPassMinTime = DateUtils.stringToLocalDateTime(start_Y + "-" + start_M_str + "-" + start_D_str + " " + psMinStr);
        log.info("goInPassMinTime:{}", DateUtils.localDateTimeToString(goInPassMinTime));

        goInPassMaxTime = DateUtils.stringToLocalDateTime(start_Y + "-" + start_M_str + "-" + start_D_str + " " + psMaxStr);
        log.info("goInPassMaxTime:{}", DateUtils.localDateTimeToString(goInPassMaxTime));


        goOutStartClockTime = DateUtils.stringToLocalDateTime(start_Y1 + "-" + start_M_str1 + "-" + start_D_str1 + " " + startStr + ":" + oo);
        log.info("goOutStartClockTime:{}", DateUtils.localDateTimeToString(goOutStartClockTime));

        goOutEndClockTime = DateUtils.stringToLocalDateTime(start_Y1 + "-" + start_M_str1 + "-" + start_D_str1 + " " + endStr + ":" + oo);
        log.info("goOutEndClockTime:{}", DateUtils.localDateTimeToString(goOutEndClockTime));

        goOutPassMinTime = DateUtils.stringToLocalDateTime(start_Y1 + "-" + start_M_str1 + "-" + start_D_str1 + " " + psMinStr);
        log.info("goOutPassMinTime:{}", DateUtils.localDateTimeToString(goOutPassMinTime));

        goOutPassMaxTime = DateUtils.stringToLocalDateTime(start_Y1 + "-" + start_M_str1 + "-" + start_D_str1 + " " + psMaxStr);
        log.info("goOutPassMaxTime:{}", DateUtils.localDateTimeToString(goOutPassMaxTime));

        log.info("start_D1:{},start_D:{}", start_D1, start_D);
        lessDay = start_D1 - start_D - 1;
        log.info("计算lessDay = start_D1 - start_D - 1得:{}", lessDay);
        if (lessDay < 0) {
            lessDay = 0;
        }
        log.info("开始时间和结束时间相差几天：lessDay:{}", lessDay);
        //跨月计算
        if (start_M != start_M1 && start_Y == start_Y1) {
            log.info("=========跨越计算开始=========");
            //入场本月的最后一天
            LocalDateTime goInLastDay = goInStart.with(TemporalAdjusters.lastDayOfMonth());
            log.info("goInLastDay:{}", DateUtils.localDateTimeToString(goInLastDay));
            String goInLastDayStr = dateTimeFormatter1.format(goInLastDay);
            LocalDate goInLastDayLd = LocalDate.parse(goInLastDayStr, dateTimeFormatter1);
            goInMothLastDay = goInLastDayLd.getDayOfMonth();
            log.info("goInMothLastDay:{}", goInMothLastDay);
            lessDay = (goInMothLastDay - start_D) + start_D1 - 1;
            log.info("跨月计算开始时间和结束时间相差几天：lessDay:{}", lessDay);
            //出场本月的第一天
            LocalDateTime goOutFirstDay = goOutEnd.with(TemporalAdjusters.firstDayOfMonth());
            log.info("goOutFirstDay:{}", DateUtils.localDateTimeToString(goOutFirstDay));
            String goOutFirstDayStr = dateTimeFormatter1.format(goOutFirstDay);
            LocalDate goOutFirstDayLd = LocalDate.parse(goOutFirstDayStr, dateTimeFormatter1);
            goOutMothFirstDay = goOutFirstDayLd.getDayOfMonth();
            log.info("goOutMothFirstDay:{}", goOutMothFirstDay);
            //入场所在天是否是本月的最后一天 且出场天是否是本月第一天
            if (start_D == goInMothLastDay && 1 == goOutMothFirstDay) {
                flag1 = Boolean.TRUE;
            }
            log.info("=========跨越计算结束=========");
        }
        //跨年
        if (start_Y1 - start_Y >= 1) {
            String startStr1 = startDt.format(dateTimeFormatter2);
            String enStr1 = endDt.format(dateTimeFormatter2);
            log.info("startStr1:{}", startStr1);
            log.info("enStr1:{}", enStr1);
            List<String> res = DateUtils.calculationDays(startStr1, enStr1);
            log.info("跨年两个时间相隔几天:{}", res.size());
            lessDay = res.size() - 2;
            log.info("跨年两个时间相隔几天减2后得:{}", lessDay);
            if (lessDay < 0) {
                lessDay = 0;
            }
        }

    }


    public Double TotalFreeTime() {
        //开始大于结束 开始等于结束
        if (goInStart.compareTo(getGoOutEnd()) >= 0) {
            return 0d;
        }
        int start_D = goInStartMap.get("start_D");
        int start_D1 = goOutEndMap.get("start_D1");
        log.info("start_D:{},start_D1:{}", start_D1, start_D);
        // 进的时间顺时针找,出的时间逆时针找
        if (lessDay == 0 && start_D == start_D1) {
            if (goInStart.compareTo(goInEndClockTime) >= 1 && goOutEnd.compareTo(goOutStartClockTime) <= 0) {
                log.info("================ 进出都在没落在计费区间直接返回0 ===========");
                return 0d;
            }
            // 一个时钟周期
            if (goInStart.compareTo(goInPassMinTime) == 0 && goOutEnd.compareTo(goOutPassMaxTime) == 0) {
                int ocf = oneClockFreeHours * 60;
                log.info("ocf:{}", ocf);
                return Double.valueOf(ocf);
            }
            log.info("================ 进出都在 同侧 (2种情况)开始 ===========");
            // 大于等于 00:00:00 小于等于 本个时钟的结束计费点 goOutEndClockTime
            if (goInStart.compareTo(goInPassMinTime) >= 0 && goOutEnd.compareTo(goOutEndClockTime) <= 0) {
                Duration between = Duration.between(goInStart, goOutEnd);
                long t1 = between.toMinutes();
                log.info("t1:{}", t1);
                return Double.valueOf(String.valueOf(t1));
            }
            // 大于等于 本个时钟的开始计费点 goInStartClockTime 小于等于 23:59:59
            if (goInStart.compareTo(goInStartClockTime) >= 0 && goOutEnd.compareTo(goInPassMaxTime) <= 0) {
                Duration between = Duration.between(goInStart, goOutEnd);
                long t2 = between.toMinutes();
                log.info("t2:{}", t2);
                return Double.valueOf(String.valueOf(t2));
            }
            log.info("================ 进出都在 同侧 (2种情况)结束 ===========");

            log.info("================ 进出都有交叉 分割的情况 (3种情况)开始 ===========");
            if (goInStart.compareTo(goInPassMinTime) >= 0
                    && goInStart.compareTo(goInEndClockTime) == -1
                    && goOutEnd.compareTo(goInStartClockTime) <= 0
                    && goOutEnd.compareTo(goInEndClockTime) >= 0) {
                Duration between = Duration.between(goInStart, goInEndClockTime);
                long t3 = between.toMinutes();
                log.info("t3:{}", t3);
                return Double.valueOf(String.valueOf(t3));
            }
            if (goOutEnd.compareTo(goInPassMaxTime) <= 0
                    && goOutEnd.compareTo(goInStartClockTime) == 1
                    && goInStart.compareTo(goInEndClockTime) >= 0
                    && goInStart.compareTo(goInStartClockTime) <= 0) {
                Duration between = Duration.between(goInStartClockTime, goOutEnd);
                long t4 = between.toMinutes();
                log.info("t4:{}", t4);
                return Double.valueOf(String.valueOf(t4));
            }
            if (goInStart.compareTo(goInPassMinTime) == 1
                    && goInStart.compareTo(goInEndClockTime) == -1
                    && goOutEnd.compareTo(goInPassMaxTime) == -1
                    && goOutEnd.compareTo(goInStartClockTime) == 1) {
                Duration between = Duration.between(goInStart, goInEndClockTime);
                long t5 = between.toMinutes();
                log.info("t5:{}", t5);
                Duration between2 = Duration.between(goInStartClockTime, goOutEnd);
                long t6 = between2.toMinutes();
                log.info("t6:{}", t6);
                long t7 = t5 + t6;
                log.info("t7:{}", t7);
                return Double.valueOf(String.valueOf(t7));
            }
            log.info("================ 进出都有交叉 分割的情况 (3种情况)结束 ===========");
        } else if (lessDay >= 1 || (start_D1 - start_D) == 1 || flag1) {
            Double heard = this.calculateHeardClock();
            Double between = this.calculateBetweenClock();
            Double tail = this.calculateTailClock();
            log.info("heard:{},between:{},tail:{}", heard, between, tail);
            Double threeSum = heard + between + tail;
            log.info("threeSum:{}", threeSum);
            return threeSum;
        }
        return 0d;
    }

    private Double calculateHeardClock() {
        if (goInStart.compareTo(goInPassMaxTime) == 0) {
            log.info("heard return 0");
            return 0d;
        }
        if (goInStart.compareTo(goInPassMinTime) == 0) {
            int t8 = oneClockFreeHours * 60;
            log.info("t8:{}", t8);
            return Double.valueOf(t8);
        }
        if (goInStart.compareTo(goInPassMinTime) == 1
                && goInStart.compareTo(goInEndClockTime) == -1) {
            Duration between2 = Duration.between(goInStart, goInEndClockTime);
            long t9 = between2.toMinutes();
            log.info("t9:{}", t9);
            Duration between3 = Duration.between(goInStartClockTime, goInPassMaxTime);
            long t10 = between3.toMinutes();
            log.info("t10:{}", t10);
            long t11 = t9 + t10;
            return Double.valueOf(t11);
        }
        if (goInStart.compareTo(goInEndClockTime) <= 0
                && goInStart.compareTo(goInEndClockTime) >= 0) {
            Duration between4 = Duration.between(goInStartClockTime, goInPassMaxTime);
            long t12 = between4.toMinutes();
            log.info("t12:{}", t12);
            return Double.valueOf(t12);
        }
        if (goInStart.compareTo(goInStartClockTime) == 1
                && goInStart.compareTo(goInPassMaxTime) <= 0) {
            Duration between4 = Duration.between(goInStart, goInPassMaxTime);
            long t19 = between4.toMinutes();
            log.info("t19:{}", t19);
            return Double.valueOf(t19);
        }
        if (goInStart.compareTo(goInEndClockTime) >= 0
                && goInStart.compareTo(goInStartClockTime) <= 0) {
            Duration between4 = Duration.between(goInStartClockTime, goInPassMaxTime);
            long t19 = between4.toMinutes();
            log.info("t19:{}", t19);
            return Double.valueOf(t19);
        }
        return 0d;
    }

    private Double calculateBetweenClock() {
        Double bt = Double.valueOf(lessDay * oneClockFreeHours * 60);
        log.info("bt:{}", bt);
        return bt;
    }

    private Double calculateTailClock() {
        if (goOutEnd.compareTo(goOutPassMinTime) == 0) {
            log.info("tail return 0");
            return 0d;
        }
        if (goOutEnd.compareTo(getGoOutPassMaxTime()) == 0) {
            int t13 = oneClockFreeHours * 60;
            log.info("t13:{}", t13);
            return Double.valueOf(t13);
        }
        if (goOutEnd.compareTo(goOutPassMinTime) == 1
                && goOutEnd.compareTo(goOutEndClockTime) == -1) {
            Duration between6 = Duration.between(goOutPassMinTime, goOutEnd);
            long t14 = between6.toMinutes();
            log.info("t14:{}", t14);
            return Double.valueOf(t14);
        }
        if (goOutEnd.compareTo(goOutEndClockTime) >= 0
                && goOutEnd.compareTo(goOutStartClockTime) <= 0) {
            Duration between7 = Duration.between(goOutPassMinTime, goOutEndClockTime);
            long t15 = between7.toMinutes();
            log.info("t15:{}", t15);
            return Double.valueOf(t15);
        }
        if (goOutEnd.compareTo(goOutPassMaxTime) == -1
                && goOutEnd.compareTo(goOutStartClockTime) == 1) {
            Duration between8 = Duration.between(goOutStartClockTime, goOutEnd);
            long t16 = between8.toMinutes();
            log.info("t16:{}", t16);

            Duration between9 = Duration.between(goOutPassMinTime, goOutEndClockTime);
            long t17 = between9.toMinutes();
            log.info("t17:{}", t17);

            long t18 = t16 + t17;
            log.info("t18:{}", t18);
            return Double.valueOf(t18);
        }
        return 0d;
    }

}